package cn.net.isir.core;

import cn.net.isir.common.ResultObject;
import cn.net.isir.common.TokenManager;
import cn.net.isir.utils.RequestUtils;
import cn.net.isir.utils.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author liuxubo
 * @filename BasicService.java
 * @package com.sq.core.common
 * @email lxb@isir.net.cn
 * @date 2018/11/06
 * @comment
 * @since 1.8
 */
@Service
@Transactional
public abstract class BasicService2<E extends BasicModel> {

    protected static Logger logger;

    private Class<E> eClass;

    public BasicService2() {
        logger = Logger.getLogger(this.getClass());
        // 一定要放在构造函数里
        eClass = (Class<E>) getModelClass(0);// 0表示第一个泛型
    }

    /**
     * 获取运行对象中实际的泛型类型
     *
     * @param index 第index个泛型
     * @return 类型
     */
    private Class<?> getModelClass(int index) {
        Type genType = this.getClass().getGenericSuperclass();// 得到泛型父类
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();//一个泛型类可能有多个泛型形参，比如ClassName<T,K> 这里有两个泛型形参T和K，Class Name<T> 这里只有1个泛型形参T
        if (params.length - 1 < index) {
            return null;
        }
        return (Class) params[index];
    }

    private BasicDao<E> basicDao = null;

    public E selectByPrimaryKey(String id) {
        injectBasicDao();
        return basicDao.selectByPrimaryKey(id);
    }

    public E selectOne(E parameter) {
        injectBasicDao();
        return basicDao.selectOne(parameter);
    }

    public List<E> selectList(E parameter) {
        injectBasicDao();
        return basicDao.selectList(parameter);
    }

    public int selectCount(E parameter) {
        injectBasicDao();
        return basicDao.selectCount(parameter);
    }

    public int update(E parameter) {
        injectBasicDao();
        //检查更新必填项是否都已填写
        ResultObject ro = RequestUtils.checkField(parameter, UpdateRequired.class);
        if (ro.getResult() != 200) {
            return 0;
        }
        return basicDao.update(parameter);
    }

    public int insert(E parameter) {
        injectBasicDao();
        //检查新增必填项是否都已填写
        ResultObject ro = RequestUtils.checkField(parameter, InsertRequired.class);
        if (ro.getResult() != 200) {
            return 0;
        }
        // 如果没有默认的创建者,则统一赋值
        if (StringUtils.isBlank(parameter.getCreateUser())) {
            parameter.setCreateUser(TokenManager.getTokenId());
        }
        return basicDao.insert(parameter);
    }

    public int delete(String id) {
        injectBasicDao();
        return basicDao.delete(id);
    }

    public PageInfo selectListByUser(Object parameter) {
        injectBasicDao();
        BasicModel model = (BasicModel) parameter;
        Integer pageNo = model.getPageNo();
        Integer pageSize = model.getPageSize();
        model.setQueryUserId(TokenManager.getTokenId());
        return basicDao.selectPageList(parameter, "selectListByUser", pageNo, pageSize);
    }

    public PageInfo<E> selectPageList(E parameter, Integer pageNo, Integer pageSize) {
        injectBasicDao();
        Map<String, Object> objectMap = new HashMap<>();
        if (parameter != null) {
            objectMap = JSONObject.parseObject(parameter.toString());
        }
        //移除分页信息，否则会报错
        if (objectMap.containsKey("pageNo")) {
            objectMap.put("pageNo", null);
        }
        if (objectMap.containsKey("pageSize")) {
            objectMap.put("pageSize", null);
        }
        return basicDao.selectPageList(objectMap, pageNo, pageSize);
    }

    /**
     * 自动注入baseDao
     */
    private void injectBasicDao() {
        //第一次没有值的时候，才进行自动注入，否则不进行注入
        if (basicDao != null) {
            return;
        }
        //反射获取所有字段
        java.lang.reflect.Field[] fields = this.getClass().getDeclaredFields();
        //循环所有字段
        for (java.lang.reflect.Field field : fields) {
            //判断当前字段是否有SetBasicDao注解
            boolean fieldHasAnno = field.isAnnotationPresent(SetBasicDao.class);
            //如果没有注解，不进行处理
            if (!fieldHasAnno) {
                continue;
            }
            //判断当前注解的字段，是否是BaseDao的子类，不是则不进行处理
            if (!BasicDao.class.isAssignableFrom(field.getType())) {
                continue;
            }
            //设置可访问性，如果不设置，访问的时候会抛出不可读异常
            field.setAccessible(true);
            //获取字段的值
            Object val = null;
            try {
                val = field.get(this);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            logger.info("auto inject:");
            logger.info(field.getName() + ":" + val);
            //赋值给basicDao
            try {
                this.basicDao = (BasicDao<E>) val;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        if (basicDao == null) {
            throw new RuntimeException("Service中的@SetBasicDao注解设置不正确，请重新检查!泛型提示:[" + Objects.requireNonNull(this.getModelClass(0)).getTypeName() + "]");
        }
    }


}
